<?php
/**
 * Helper
 *
 * 常用工具箱
 *
 * @author   songhuan <iphper@yeah.net>
 * @version   $Id: Helper.php 1 2010-08-10 14:40:00Z $
 */
class Helper
{
	/**
	 * 获取当前链接地址
	 * 
	 * @return string 链接地址
	 */
	public static function getUrl()
	{
		if (!empty($_SERVER['REQUEST_URI'])) 
			return $_SERVER['REQUEST_URI'];
		else 
		{
			if (empty($_SERVER['QUERY_STRING'])) 
				return $_SERVER['PHP_SELF'];
			else 
				return $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
		}
	}
	
	/**
	 * 获取客户端IP地址
	 * 
	 * @return string ip
	 */
	public static function getIp() 
	{
		$direct_ip = '';
		// Gets the default ip sent by the user
		if (!empty($_SERVER['REMOTE_ADDR'])) 
			$direct_ip = $_SERVER['REMOTE_ADDR'];
		
		// Gets the proxy ip sent by the user
		$proxy_ip = '';
		if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) 
			$proxy_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		else if (!empty($_SERVER['HTTP_X_FORWARDED'])) 
			$proxy_ip = $_SERVER['HTTP_X_FORWARDED'];
		else if (!empty($_SERVER['HTTP_FORWARDED_FOR'])) 
			$proxy_ip = $_SERVER['HTTP_FORWARDED_FOR'];
		else if (!empty($_SERVER['HTTP_FORWARDED'])) 
			$proxy_ip = $_SERVER['HTTP_FORWARDED'];
		else if (!empty($_SERVER['HTTP_VIA'])) 
			$proxy_ip = $_SERVER['HTTP_VIA'];
		else if (!empty($_SERVER['HTTP_X_COMING_FROM'])) 
			$proxy_ip = $_SERVER['HTTP_X_COMING_FROM'];
		else if (!empty($_SERVER['HTTP_COMING_FROM'])) 
			$proxy_ip = $_SERVER['HTTP_COMING_FROM'];
			
		// Returns the true IP if it has been found, else false
		if (empty($proxy_ip)) 
			// True IP without proxy
			return $direct_ip;
		else 
		{
			$is_ip = preg_match('|^([0-9]{1,3}\.){3,3}[0-9]{1,3}|', $proxy_ip, $regs);
			if ($is_ip && (count($regs) > 0)) 
				// True IP behind a proxy
				return $regs[0];
			else 
				// Can't define IP: there is a proxy but we don't have
				// information about the true IP
				return $direct_ip;
		}
	}
	
	/**
	 * 装换字符串编码
	 * 
	 * @param string $str 需要转换的字符串
	 * @param string $out_charset 转换后的编码
	 * @return string 转换后的字符串
	 */
	public static function convertEncoding($str, $out_charset = null)
	{
		if (null === $out_charset)
			$out_charset = V::$config['web']['charset'];
		
		$in_charset = mb_detect_encoding($str, 'GBK, UTF-8, GB2312, ASCII');
		return mb_convert_encoding($str, $out_charset, $in_charset);
	}
	
	/**
	 * 弹出消息框，并跳转到指定链接，如果链接为空，跳转到前一个链接
	 * 
	 * @param string $msg 需要弹出的消息
	 * @param string $url 跳转的链接地址
	 * @return void
	 */
	public static function alertMsg($msg = null, $url = null)
	{
		$url = (null === $url) ? 'history.go(-1);' : "window.location.href = '$url'";
		$html  = "<meta http-equiv='content-Type' content='text/html; charset=utf-8' />\r\n";
		$html .= "<script language='javascript' type='text/javascript'>\r\n";
		if (null !== $msg)
			$html .= "alert('$msg');\r\n";

		$html .= "location: $url\r\n";
		$html .= '</script>';
		exit($html);
	}
	
	/**
	 * 随机字符串
	 * 
	 * @param string $format: ALL(英文字母加数字),LETTER(字母),NUMBER(数字)
	 * @return string 随机字符串
	 */
	public static function randStr($len = 4, $format = 'ALL') 
	{
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 
		$start = $format=='NUMBER' ? 52 : 0;
		$end = $format=='LATTER' ? 51 : 61;
		$str = '';
		for ($i=0; $i<$len; $i++)
			$str .= $chars{mt_rand($start, $end)};
		
		return $str;
	}

	/**
	 * GBK编码字符双字节截串，一个汉字占一个字符
	 * 
	 * @param string $str
	 * @param int $start
	 * @param int $length
	 * @return string 截取后的字符串
	 */
	public static function gbkDSubstr($str, $start = 0, $length = -1) 
	{
		$substr = '';
		$str = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;', '&nbsp;'), 
						   array('&', '"', '<', '>', ' '), $str);
		$strlen = strlen($str);
		for ($i=0; $i<$strlen; $i++) 
		{
			if (ord($str[$i]) > 128) 
				$str_split[] = $str[$i].$str[++$i];
			else 
				$str_split[] = $str[$i];
		}
		
		$count = count($str_split);
		$sublen = $count - $start;
		if ($sublen > 0) 
		{
			$length = $length < 0 ? $sublen : $length;
			$cutpoint = $length < $sublen ? $start + $length : $start + $sublen;
			for ($i=$start; $i<$cutpoint; $i++) 
				$substr .= $str_split[$i];
				
		}
		$substr = str_replace(array('&', '"', '<', '>', ' '), 
							  array('&amp;', '&quot;', '&lt;', '&gt;', '&nbsp;'), $substr);
		return $substr;
	}

	/**
	 * GBK编码字符单字节截串，一个汉字占两个字符
	 * 
	 * @param string $str
	 * @param int $start
	 * @param int $length
	 * @return string 截取后的字符串
	 */
	public static function gbkSSubstr($str, $start = 0, $length = -1) {
		$substr = '';
		$str = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;', '&nbsp;'), 
						   array('&', '"', '<', '>', ' '), $str);
		$strlen = strlen($str);
		if ($strlen > 0) 
		{
			$end = $length < 0 || ($start + $length) > $strlen? $strlen : $start + $length;
			$c = '';
			for ($i=0; $i<=$strlen; $i++) 
			{
				if ($start==0 || $i>$start) 
					$substr .= $c;
					
				if (ord($str[$i]) > 128) 
					$c = $str[$i].$str[++$i];
				else 
					$c = $str[$i];
					
				if ($i>=$end) 
					break;
			}
		}
		$substr = str_replace(array('&', '"', '<', '>', ' '), 
							  array('&amp;', '&quot;', '&lt;', '&gt;', '&nbsp;'), $substr);
		return $substr;
	}

	/**
	 * UTF-8编码字符双字节截串，一个汉字占一个字符
	 * 
	 * @param string $str
	 * @param int $start
	 * @param int $length
	 * @return string 截取后的字符串
	 */
	public static function utf8DSubstr($str, $start = 0, $length = -1) 
	{
		if ($length === -1)
			$length = strlen($str);
			
		return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $start . '}'.
		'((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $length . '}).*#s',
		'$1', $str);
	}

	/**
	 * UTF-8编码字符单字节截串，一个汉字占两个字符
	 * 
	 * @param string $str
	 * @param int $start
	 * @param int $length
	 * @return string 截取后的字符串
	 */
	public static function utf8SSubstr($str, $start = 0, $length = -1) 
	{
		$str = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), 
						   array('&', '"', '<', '>'), $str);
		
		$strlen = strlen($str);
		if ($length === -1) $length = $strlen;
		$end = $start + $length;
		if ($start === 0) $end++;
		$n = $tn = $noc = 0;
		$b = true;
		while ($n < $strlen) 
		{
			$t = ord($str[$n]);
			if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
				$tn = 1; $n++; $noc++;
			}
			else if (194 <= $t && $t <= 223) { 
				$tn = 2; $n += 2; $noc += 2;
			}
			else if (224 <= $t && $t <= 239) { 
				$tn = 3; $n += 3; $noc += 2;
			}
			else if (240 <= $t && $t <= 247) { 
				$tn = 4; $n += 4; $noc += 2;
			}
			else if (248 <= $t && $t <= 251) { 
				$tn = 5; $n += 5; $noc += 2;
			}
			else if ($t == 252 || $t == 253) { 
				$tn = 6; $n += 6; $noc += 2;
			}
			else 
				$n++;
			
			if ($b && $noc >= $start) 
			{
				if ($noc === $start)
					$start = $n;
				else 
				{
					$start = $n - $tn;
					$end--;
				}
				$b = false;
			}
			
			if ($noc >= $end) break;
		}
		if ($noc > $end) $n -= $tn;
		
		$substr = substr($str, $start, $n-$start);
		$substr = str_replace(array('&', '"', '<', '>'), 
							  array('&amp;', '&quot;', '&lt;', '&gt;'), $substr);
		return $substr;
	}
	
	/**
	 * 验证验证是否正确
	 * 
	 * @param string $vcode
	 * @return boolean 
	 */
	public static function cmpVcode($vcode)
	{
		$vcode = isset($_POST['vcode']) ? trim($_POST['vcode']) : 
			(isset($_GET['vcode']) ? trim($_GET['vcode']) : ''); 
		if (empty($vcode)) 
			return false;
		
		return (!empty($_SESSION['verifycodes'])) && 
				(strcmp($_SESSION['verifycodes'], md5(strtoupper($vcode))) === 0);
	}
	
	/**
	 * CURL方法PHP模拟Form表单提交
	 * 
	 * @param string $url
	 * @param string $method
	 * @return string 接受数据页面处理后返回的串
	 */
	public static function curlSubmit($url, $method = 'POST')
	{
		$method = strtoupper($method);
		$isPost = (strcmp('POST', $method) === 0);
		$urls = parse_url($url);
		if ($isPost)
			$url = $urls['scheme'] . '://' . $urls['host'] . $urls['path'];
			
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 			 $url);           //指定读取$url
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);  	          //最长连接时间
		curl_setopt($ch, CURLOPT_TIMEOUT, 		 30);             //最长执行时间
		curl_setopt($ch, CURLOPT_HEADER, 		 0);	          //返回内容中不包含HTTP头
		if ($isPost) 
		{
			curl_setopt($ch, CURLOPT_POST, 	     1);	          //发送POST请求,与表单提交效果是一样的
			curl_setopt($ch, CURLOPT_POSTFIELDS, $urls['query']); //发送POST时,可以发的参数内容
		}
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);           //将服务器返回的Location放在header中递归返回给服务器
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);              //将curl_exec()获取的信息以文件流的形式返回,而不直接输出
		$result = curl_exec($ch);  //执行
		if (curl_errno($ch) !== 0) 
			$result = false;
			
		curl_close($ch);
		return $result;
	}
	
	/**
	 * fsockopen方法PHP模拟Form表单提交
	 * 
	 * @param string $url
	 * @param string $method
	 * @return string 接受数据页面处理后返回的串
	 */
	public static function sockSubmit($url, $method = 'POST')
	{
		$urls = parse_url($url);
		$errno = 0;
		$errstr = $transports = $result = $path = $contentType = '';
		if(strcmp($urls['scheme'], 'https') === 0) 
		{
			$transports = 'ssl://';
			$urls['port'] = '443';
		}
		else 
		{
			$transports = 'tcp://';
			$urls['port'] = '80';
		}
		
		if (strcmp('localhost', $urls['host']) === 0) 
			$urls['host'] = '127.0.0.1';
		
		$stream = @fsockopen($transports . $urls['host'], $urls['port'], $errno, $errstr, 10);
		if (!$stream)
			throw new Exception("ERROR: $errno - $errstr");
		
		$method = strtoupper($method);
		if (strcmp('POST', $method) === 0) 
		{
			$path = $urls['path'];
			$contentType = 'application/x-www-form-urlencoded';
		}
		else 
		{
			$path = $url;
			$contentType = 'text/html';
		}
		
		fwrite($stream, "$method $path HTTP/1.1\r\n");
		fwrite($stream, "Host: {$urls['host']}\r\n");
		fwrite($stream, "Content-Type: $contentType\r\n");
		fwrite($stream, "Content-Length: " . strlen($urls['query']) . "\r\n");
		fwrite($stream, "Connection: close\r\n\r\n");
		fwrite($stream, "{$urls['query']}\r\n\r\n");
			
		while(!feof($stream)) 
			$result .= @fgets($stream, 1024);
		
		fclose($stream);
		return $result;
	}

	/**
	 * 过滤表单提交的数据
	 * 
	 * @param string $str
	 * @return string 过滤后的字符串
	 */
	public static function sanitize($str)
    {
        $ret = preg_replace("/[\r\n]+/", ' ', $str);
		return htmlspecialchars(trim($ret));
    }

    /**
     * 转义字符串或数组
     * 
     * @param string|array $param
     * @return string|array 转义后的字符串或者数组
     */
	public static function addslashes($param) 
	{
		if (is_array($param)) 
		{
			foreach ($param as $key => $val) 
				$param[$key] = self::addslashes($val);
		} 
		else 
			$param = addslashes($param);
			
		return $param;
	}
	
	/**
	 * 上传图片
	 * 
	 * @param array $file 图片信息
	 * @param int &$result 反馈消息
	 * @param string $filedir 图片上传到的目录
	 * @param string $filename 文件重定义的名称
	 * @param int $maxsize 限制最大上传文件大小
	 * @return boolean 是否上传成功
	 */
	public static function upload($file = array(), &$result, $filedir = null, $filename = null, $maxsize = null) 
	{
		foreach ($file as $value)
		{
			if (preg_match('/\.(' . V::$config['update']['type_notallow'] . ')$/i', $value)) 
			{
				$result = V::$prompts['update'][0];
				return false;
			}
		}
		$file['name'] = trim(preg_replace('/[ \r\n\t\*\%\\/\?><\|\":]{1,}/', '', $file['name']));
		if (!preg_match('/\.(' . V::$config['update']['type_img_allow'] . ')$/i', $file['name'])) 
		{
			$result = str_replace('{type_img_allow}', V::$config['update']['type_img_allow'], V::$prompts['update'][1]);
			return false;
		}
		
		if (null === $filename) 
			$filename = $file['name'];
		else if (false === strpos($filename, '.')) 
			$filename .= strrchr($file['name'], '.'); 
		else if (!preg_match('/\.(' . V::$config['update']['type_img_allow'] . ')$/i', $filename)) 
		{
			$result = str_replace('{type_img_allow}', V::$config['update']['type_img_allow'], V::$prompts['update'][1]);
			return false;
		}
		
		$file['type'] = strtolower(trim($file['type']));
		if (!in_array($file['type'], V::$config['update']['type_array'])) 
		{
			$result = V::$prompts['update'][2];
			return false;
		}

		if (null !== $maxsize && $file['size'] > $maxsize) 
		{
			$result = str_replace('{maxsize}', $maxsize, V::$prompts['update'][3]);
			return false;
		}
		
		if (null === $filedir)
			$filedir = APP_DIR . DS . 'update';
		
		if (!is_dir($filedir))
			@mkdir($filedir, 0777);

		$filepath = $filedir . DS . $filename;
		if (is_file($filepath))
			@unlink($filepath);

		$result = move_uploaded_file($file['tmp_name'], $filepath);
		@unlink($file['tmp_name']);
		if ($result) 
		{
			$result = V::$prompts['update'][5];
			return true;
		}
		$result = V::$prompts['update'][4];
		return false;
	}
	
}
